#include "Graph.h"
#include "Utils.h"

int Graph::COLORS_COUNT = 7;
char* Graph::COLORS[] = {
	"red",
	"green",
	"blue",
	"cyan",
	"yellow",
	"orange",
	"magenta",
};

double Graph::MAX_DOUBLE = 1E+300;

void Graph::graphDESolution(vector<NodeSolution*>* solution, double startFromX) {
	if (solution == nullptr) {
		return;
	}

	auto it = solution->begin();
	auto end = solution->end();
	int count = solution->size();
	while (it != end) {
		if ((*it) == nullptr || (*it)->getX() < startFromX) {
			it++;
			count--;
			continue;
		}

		break;
	}

	if (it == end) {
		return;
	}

	NodeSolution* first = *it;
	int dim;
	if (first == nullptr || (dim = first->getDim()) < 1) {
		return;
	}

	double* x = new double[count];
	double** y = Utils::allocateDoubleTwoDimArray(dim, count);

	int i = 0;
	double minX = MAX_DOUBLE;
	double maxX = -MAX_DOUBLE;
	double minY = MAX_DOUBLE;
	double maxY = -MAX_DOUBLE;
	double prevX = -MAX_DOUBLE;
	while (it != end) {
		NodeSolution* sln;
		double nodeX;
		if ((sln = *it) == nullptr || sln->getDim() != dim || (nodeX = sln->getX()) <= prevX) {
			Utils::freeTwoDimArray(y, dim);
			delete[] x;
			return;
		}

		x[i] = nodeX;
		updateMin(minX, nodeX);
		updateMax(maxX, nodeX);

		double* nodeY = sln->getY();
		for (int j = 0; j < dim; j++) {
			y[j][i] = nodeY[j];
			updateMin(minY, nodeY[j]);
			updateMax(maxY, nodeY[j]);
		}

		i++;
		it++;
		prevX = nodeX;
	}

	Dislin* g = makeGraphScene(minX, maxX, minY, maxY);
	for (int j = 0; j < dim; j++) {
		g->color(COLORS[j % COLORS_COUNT]);
		g->curve(x, y[j], count);
	}

	g->disfin();

	delete g;
	Utils::freeTwoDimArray(y, dim);
	delete[] x;
}

Dislin* Graph::makeGraphScene(double minX, double maxX, double minY, double maxY) {
	Dislin* g = new Dislin();

	g->metafl("cons");
	g->scrmod("revers");
	g->disini();
	g->pagera();
	g->complx();
	g->axspos(450, 1800);
	g->axslen(2200, 1200);

	g->name("X-axis", "x");
	g->name("Y-axis", "y");

	g->labdig(2, "x");
	g->labdig(2, "y");
	g->ticks(10, "x");
	g->ticks(10, "y");

	g->titlin("Graph of differential equations system solution", 1);

	int ic = g->intrgb(0.95, 0.95, 0.95);
	g->axsbgd(ic);

	g->graf(minX, maxX, minX, (maxX - minX) / 4.0, minY, maxY, minY, (maxY - minY) / 4.0);
	g->setrgb(0.7, 0.7, 0.7);
	g->grid(1, 1);

	g->color("fore");
	g->height(50);
	g->title();

	return g;
}

void Graph::updateMin(double& currentMin, double newValue) {
	if (newValue < currentMin) {
		currentMin = newValue;
	}
}

void Graph::updateMax(double& currentMax, double newValue) {
	if (newValue > currentMax) {
		currentMax = newValue;
	}
}